<template>
  <div
    class="h-lazyload__box"
    :style="{
      backgroundColor: placeholder ? 'transparent' : backgroundColor,
      width: width,
      height: height ? height : 'auto',
      borderRadius: radius,
    }"
    @click="handleClick"
  >
    <img
      ref="imgRef"
      class="h-lazyload__img"
      :class="{
        'tui-img__hidden': !placeholder && fadeShow && !show,
        'tui-img__appear': show && !placeholder && fadeShow,
      }"
      :style="{ height: height, borderRadius: radius }"
      :src="show ? src : placeholder"
      :id="elId"
    />
  </div>
  <slot></slot>
</template>

<script setup lang="ts">
import { ref, watch, onUnmounted, onMounted } from "vue";
import type { LazyloadProps, LazyloadEmits } from "./types";
import useEventListener from "../../hooks/useEventListener";

const {
  src = "",
  placeholder = "",
  backgroundColor = "#E7E7E7",
  fadeShow = true,
  width = "340px",
  height = "340px",
  radius = '0',
  bottom = 50,
  disconnect = false,
  index = 0,
} = defineProps<LazyloadProps>();
const emits = defineEmits<LazyloadEmits>();
const show = ref(false);
const imgRef = ref();
// 交叉观察器实例
let observer: IntersectionObserver | null = null;

// 生成当前时间的时间戳+随机数的唯一性的字符串
const unique = (n = 6) => {
  let rnd = "";
  for (let i = 0; i < n; i++) rnd += Math.floor(Math.random() * 10);
  return "tui_" + new Date().getTime() + rnd;
};

// 图片id
let elId = unique() + index;

onMounted(() => {
  if (!disconnect && window.self === window.top) {
    createObserver();
  } else {
    show.value = true;
  }
});

// 清除观察器
const removeObserver = () => {
  if (observer) {
    observer.disconnect();
    observer = null;
  }
};


// 创建交叉观察器
const createObserver = () => {
  if (observer || show.value) return;
  let options = {
    root: null,
    rootMargin: `0px 0px ${bottom}px 0px`,
    threshold: 0,
  };

  observer = new IntersectionObserver(handleIntersect, options);
  observer.observe(imgRef.value);
};


// 当数值大于0的时候显示加载
const handleIntersect = (entries: IntersectionObserverEntry[]) => {
  if (entries[0].intersectionRatio > 0 && !show.value) {
    show.value = true;
    removeObserver();
  }
};

const handleClick = () => {
  emits("click", index);
};

useEventListener(imgRef, "onload", (e) => {
  emits("load", index, e.target);
});

useEventListener(imgRef, "onerror", (e) => {
  emits("error", index, e.target);
});

watch(
  () => disconnect,
  (newValue) => {
    if (newValue) {
      removeObserver();
    }
  }
);

onUnmounted(() => {
  removeObserver();
});
</script>

<style scoped></style>
